package com.hifar.test.entrust.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ZipUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hifar.abi.flow.bean.prd.NodeUserBean;
import com.hifar.abi.flow.bean.pri.PriCreateBean;
import com.hifar.abi.flow.bean.pri.TaskCommitBean;
import com.hifar.abi.flow.utils.FlowApiUtils;
import com.hifar.abi.flow.utils.FlowConst;
import com.hifar.base.serialNo.service.IBaseSerialNoService;
import com.hifar.constant.FlowCodeConsts;
import com.hifar.fw.json.JsonUtils;
import com.hifar.fw.utils.bean.BusiRequest;
import com.hifar.fw.utils.id.IdUtils;
import com.hifar.log.AutoLogUtils;
import com.hifar.plat.AopOption.DictModel;
import com.hifar.plat.baseModal.pojo.BaseOssFiles;
import com.hifar.plat.baseModal.service.IBaseOssFilesService;
import com.hifar.plat.baseModal.service.IBaseSysDictClassifyService;
import com.hifar.plat.dept.pojo.BaseOrgDeptPlat;
import com.hifar.plat.dept.service.IBaseOrgDeptPlatService;
import com.hifar.plat.maindatasource.service.IMainDataSourceService;
import com.hifar.plat.officUtil.ExcelTemplateUtil;
import com.hifar.plat.user.pojo.BaseOrgUserPlat;
import com.hifar.plat.user.service.IBaseOrgUserService;
import com.hifar.sys.BusiResponse;
import com.hifar.sys.BusiResponseNetty;
import com.hifar.sys.MinioUtil;
import com.hifar.sys.SystemLoginUser;
import com.hifar.test.api.model.SyncUserInfo;
import com.hifar.test.debugApi.client.DebugApiClient;
import com.hifar.test.entrust.constant.*;
import com.hifar.test.entrust.mapper.HfEnvEntrustMapper;
import com.hifar.test.entrust.model.EntrustPieceQrData;
import com.hifar.test.entrust.model.EntrustProjectQrData;
import com.hifar.test.entrust.model.EntrustQRData;
import com.hifar.test.entrust.model.QrData;
import com.hifar.test.entrust.pojo.*;
import com.hifar.test.entrust.pojo.VO.*;
import com.hifar.test.entrust.render.HfEnvEntrustQrRender;
import com.hifar.test.entrust.service.*;
import com.hifar.test.oaApi.client.OaTaskClient;
import com.hifar.test.product.service.IHfProductBaseService;
import com.hifar.test.report.pojo.HfEnvReport;
import com.hifar.test.report.service.IHfEnvReportService;
import com.hifar.test.task.pojo.HfEnvTask;
import com.hifar.test.task.pojo.VO.HfEnvTaskTestVO;
import com.hifar.test.task.service.IHfEnvTaskService;
import com.hifar.test.test.pojo.HfEnvTaskTestRelation;
import com.hifar.test.test.service.IHfEnvTaskTestRelationService;
import com.hifar.test.test.service.IHfEnvTestService;
import com.hifar.test.dailydisplacement.pojo.HfDailyDisplacement;
import com.hifar.test.dailydisplacement.service.IHfDailyDisplacementService;
import com.hifar.test.unit.pojo.HfPrjUnitBase;
import com.hifar.test.unit.service.IHfPrjUnitBaseService;
import com.hifar.utils.FileUtil;
import com.hifar.utils.ItextpdfUtil;
import com.hifar.utils.QRCodeUtil;
import com.hifar.utils.ToolKit;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 委托单
 */
@Service
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public class HfEnvEntrustServiceImpl extends ServiceImpl<HfEnvEntrustMapper, HfEnvEntrust> implements IHfEnvEntrustService {

    private static final Logger log = LoggerFactory.getLogger(HfEnvEntrustServiceImpl.class);

    @Autowired
    private AutoLogUtils autoLogUtils;

    @Autowired
    private IBaseSysDictClassifyService sysDictClassifyService;

    @Autowired
    private IHfPrjUnitBaseService hfPrjUnitBaseService;

    @Autowired
    private IHfProductBaseService productBaseService;

    @Autowired
    private IBaseSerialNoService baseSerialNoService;

    @Autowired
    private IHfEnvPieceService hfEnvPieceService;

    @Autowired
    private IMainDataSourceService dataSourceService;

    @Autowired
    private IHfEnvProjectService hfEnvProjectService;

    @Autowired
    private IBaseOssFilesService baseOssFilesService;

    @Autowired
    private IBaseOrgUserService baseOrgUserService;

    @Autowired
    private IHfEnvTaskService envTaskService;

    @Autowired
    private IHfEnvTestService testService;

    @Autowired
    private IHfEnvGkEntrustService gkEntrustService;

    @Autowired
    private IHfEnvGkProjectService gkProjectService;

    @Autowired
    private IHfEnvTaskTestRelationService taskTestRelationService;

    @Autowired
    private IHfEnvGkPieceService gkPieceService;

    @Autowired
    private IHfEnvReportService reportService;

    @Autowired
    private HfEnvEntrustQrRender envEntrustQrRender;

    @Autowired
    private IHfDailyDisplacementService dailyDisplacementService;

    @Autowired
    private IBaseOrgDeptPlatService baseOrgDeptPlatService;

    @Autowired
    private HfEnvEntrustAsyncService entrustAsyncService;

    @Autowired
    private OaTaskClient oaTaskClient;

    @Autowired
    private DebugApiClient debugApiClient;

    @Override
    public void copyById(String id) {
        HfEnvEntrust newEntrust = this.getById(id);
        Assert.notNull(newEntrust, "数据不存在!");
        String entrustCode = newEntrust.getEntrustCode();
        newEntrust.setId(null);
        newEntrust.setStatus(EntrustConsts.WTD_STATUS_CG);
        newEntrust.setEntrustTime(new Date());
        newEntrust.setPredictFinishTime(null);
        newEntrust.setEntrustCode(null);
        newEntrust.setFlowId(null);
        newEntrust.setCreateTime(null);
        newEntrust.setCreateUserId(null);
        newEntrust.setCreateUserName(null);
        newEntrust.setUpdateTime(null);
        newEntrust.setUpdateUserId(null);
        newEntrust.setUpdateUserName(null);
        newEntrust.setDataPackagePath(null);
        newEntrust.setQrPdfPath(null);
        newEntrust.setUpdateUserName(null);
        newEntrust.setDataSource(EntrustConsts.IN_DATA_SOURCE);
        boolean flag = this.save(newEntrust);
        Assert.isTrue(flag, "保存失败!");
        List<HfEnvPiece> pieceList = hfEnvPieceService.listByEntrustId(id);
        List<HfEnvProject> projectList = hfEnvProjectService.listByEntrustId(id);
        String newEntrustId = newEntrust.getId();
        for (HfEnvPiece envPiece : pieceList) {
            envPiece.setId(null);
            envPiece.setEntrustId(newEntrustId);
            envPiece.setCreateTime(null);
            envPiece.setCreateUserId(null);
            envPiece.setCreateUserName(null);
            envPiece.setUpdateTime(null);
            envPiece.setUpdateUserId(null);
            envPiece.setUpdateTime(null);
            envPiece.setPieceNo(null);
        }
        for (HfEnvProject hfEnvProject : projectList) {
            hfEnvProject.setId(null);
            hfEnvProject.setEntrustId(newEntrustId);
            hfEnvProject.setTestCondition(null);
        }
        hfEnvPieceService.saveBatch(pieceList);
        hfEnvProjectService.saveBatch(projectList);
        QueryWrapper<BaseOssFiles> testOutlineQueryWrapper = new QueryWrapper<>();
        testOutlineQueryWrapper.lambda()
                .eq(BaseOssFiles::getRefId, id)
                .eq(BaseOssFiles::getRefType, EntrustConsts.WTD_OUTLINE_REF_TYPE);
        List<BaseOssFiles> testOutlineList = baseOssFilesService.list(testOutlineQueryWrapper);
        for (BaseOssFiles baseOssFiles : testOutlineList) {
            baseOssFiles.setId(null);
            baseOssFiles.setRefId(newEntrustId);
            baseOssFiles.setCreateTime(null);
            baseOssFiles.setCreateUserId(null);
            baseOssFiles.setCreateUserName(null);
        }
        baseOssFilesService.saveBatch(testOutlineList);
        autoLogUtils.addLog("试验管理-委托管理", String.format("复制委托单:【%s】", entrustCode));
    }

    @Override
    public void entrustFinish(String id) {
        HfEnvEntrust envEntrust = this.getById(id);
        Assert.notNull(envEntrust, "数据不存在!");
        String status = envEntrust.getStatus();
        String entrustCode = envEntrust.getEntrustCode();

        // 幂等性检查：避免重复审批
        if (Objects.equals(EntrustConsts.WTD_STATUS_SPTG, status)) {
            log.warn("委托单已审批通过，无需重复操作，委托单号：{}", entrustCode);
            return;
        }

        // 审批通过 更新样品编号
        List<HfEnvPiece> pieceList = hfEnvPieceService.listByEntrustId(id);
        for (int i = 0; i < pieceList.size(); i++) {
            HfEnvPiece envPiece = pieceList.get(i);
            // 生成样品编号：委托单号 + 两位补零的序号
            String pieceNo = String.format("%s%s", entrustCode, ToolKit.supplementZero(String.valueOf(i + 1), 2));
            envPiece.setPieceNo(pieceNo);
            // 保存产品信息到产品基础库
            productBaseService.saveOnExist(envPiece.getProductAlias(), envPiece.getProductCode(), envPiece.getProductName());
        }

        // 更新委托单状态为审批通过
        envEntrust.setStatus(EntrustConsts.WTD_STATUS_SPTG);
        this.updateById(envEntrust);
        hfEnvPieceService.updateBatchById(pieceList);

        // 记录操作日志
        autoLogUtils.addLog("试验管理-委托管理", String.format("审批通过委托单:【%s】", entrustCode));

        // 异步生成二维码文件（不阻塞审批流程）
        entrustAsyncService.asyncGenerateQrCodeFile(id, entrustCode);

        // 异步生成数据包文件（不阻塞审批流程）
        entrustAsyncService.asyncGeneratePackageData(id, entrustCode);

        debugApiClient.syncEntrustStatus(id);
        log.info("委托单审批完成，文件生成任务已提交至后台异步执行，委托单号：{}", entrustCode);
    }


    @Override
    public void issued(String entrustId) {
        HfEnvEntrust envEntrust = this.getById(entrustId);
        Assert.notNull(envEntrust, "委托数据不存在!");
        String entrustStatus = envEntrust.getStatus();
        Assert.isTrue(Objects.equals(entrustStatus, EntrustConsts.WTD_STATUS_SPTG), "委托单状态不正确,无法下发!");
        String entrustCode = envEntrust.getEntrustCode();
        List<HfEnvProject> projectList = hfEnvProjectService.listByEntrustId(entrustId);
        for (int i = 0; i < projectList.size(); i++) {
            HfEnvProject hfEnvProject = projectList.get(i);
            String projectId = hfEnvProject.getId();
            String unitCode = hfEnvProject.getUnitCode();
            String unitName = hfEnvProject.getUnitName();
            String unitId = hfEnvProject.getUnitId();
            HfEnvTask hfEnvTask = new HfEnvTask();
            hfEnvTask.setProjectId(projectId);
            hfEnvTask.setIzExtAssistance(ExtAssistanceConsts.NO_EXT_ASSISTANCE);
            hfEnvTask.setStandardId(hfEnvProject.getStandardId());
            hfEnvTask.setStandardCode(hfEnvProject.getStandardCode());
            hfEnvTask.setStandardName(hfEnvProject.getStandardName());
            hfEnvTask.setUnitId(hfEnvProject.getUnitId());
            hfEnvTask.setUnitCode(unitCode);
            hfEnvTask.setUnitName(unitName);
            hfEnvTask.setEntrustId(entrustId);

            HfPrjUnitBase hfPrjUnitBase = hfPrjUnitBaseService.getById(unitId);


            hfEnvTask.setUnitTypeName(hfPrjUnitBase.getClassifyName());

            hfEnvTask.setTestCondition(hfEnvProject.getTestCondition());
            hfEnvTask.setEntrustCode(entrustCode);
            hfEnvTask.setStatus(TaskConsts.TASK_STATUS_CG);
            hfEnvTask.setRowSort(i);
            String taskCode = String.format("%s%s", entrustCode, ToolKit.supplementZero(String.valueOf(i + 1), 2));
            hfEnvTask.setTaskCode(taskCode);
            envTaskService.save(hfEnvTask);
        }
    }

    @Override
    public BusiResponse exportExcel(QueryWrapper<HfEnvEntrust> queryWrapper) {
        BusiResponse<Object> response = new BusiResponse<>();
        List<HfEnvEntrust> dataList = this.list(queryWrapper);
        Set<Integer> secretLevelSet = new HashSet<>();

        final Map<String, String> entrustStatusMap = new HashMap() {
            {
                put(EntrustConsts.WTD_STATUS_CG, "草稿");
                put(EntrustConsts.WTD_STATUS_SHBH, "审核驳回");
                put(EntrustConsts.WTD_STATUS_TJ, "提交");
                put(EntrustConsts.WTD_STATUS_SPTG, "审核通过");
                put(EntrustConsts.WTD_STATUS_ZXZ, "执行中");
                put(EntrustConsts.WTD_STATUS_YWC, "已完成");
                put(EntrustConsts.WTD_STATUS_CANCEL, "已作废");
            }
        };

        List<HfEnvEntrustExportVO> exportVOList = dataList.stream()
                .map(item -> {
                    HfEnvEntrustExportVO hfEnvEntrustExportVO = new HfEnvEntrustExportVO();
                    BeanUtils.copyProperties(item, hfEnvEntrustExportVO);
                    String status = item.getStatus();
                    String statusText = entrustStatusMap.get(status);

                    hfEnvEntrustExportVO.setStatusText(statusText);
                    secretLevelSet.add(item.getSecretLevel());
                    return hfEnvEntrustExportVO;
                }).collect(Collectors.toList());

        Integer maxSecretLve = secretLevelSet.stream().max(Integer::compareTo).orElse(0);
        Map<String, Object> extMap = new HashMap<>();
        extMap.put("secretLve", maxSecretLve);

        List<DictModel> dataSecretList = sysDictClassifyService.queryDictItemsByCode("hf_sys_datasecret");
        Map<String, String> dataSecretMap = dataSecretList.stream()
                .collect(Collectors.toMap(
                        item -> item.getValue(),
                        item -> item.getText(),
                        (o1, o2) -> o1
                ));
        String secretLevelText = dataSecretMap.get(com.hifar.fw.utils.lang.StringUtils.trimNull(maxSecretLve));
        extMap.put("secretLevelText", secretLevelText);
        response.setExt(extMap);
        ExcelTemplateUtil.exportExcel(response, exportVOList, HfEnvEntrustExportVO.class, "委托单数据", "委托单导出");
        autoLogUtils.addLog("试验管理-委托管理", "导出委托单Excel");
        return response;
    }

    @Override
    public void deleteAndFlowByIds(List<String> idList) {
        List<HfEnvEntrust> delEntrustList = this.listByIds(idList);
        List<String> flowIdList = new ArrayList<>();
        List<String> entrustCodeList = new ArrayList<>();
        for (HfEnvEntrust hfEnvEntrust : delEntrustList) {
            String flowId = hfEnvEntrust.getFlowId();
            flowIdList.add(flowId);
            String status = hfEnvEntrust.getStatus();
            Assert.isTrue(Arrays.asList(EntrustConsts.WTD_STATUS_CG, EntrustConsts.WTD_STATUS_SHBH, EntrustConsts.WTD_STATUS_CANCEL)
                            .contains(status)
                    , "只能删除审批驳回和草稿状态委托单!");
            String entrustCode = hfEnvEntrust.getEntrustCode();
            if (Objects.nonNull(entrustCode)) {
                entrustCodeList.add(entrustCode);
            }
        }
        if (!flowIdList.isEmpty()) {
            // 流程实例
            String deletePriSql = "delete  from  flow_pri_base where "
                    + ToolKit.generateInSql("id", flowIdList.size(), 0);
            dataSourceService.delete(deletePriSql, flowIdList.toArray());

            // 任务列表
            String deleteTaskSql = "delete from  flow_pri_task where  "
                    + ToolKit.generateInSql("pri_id", flowIdList.size(), 0);
            dataSourceService.delete(deleteTaskSql, flowIdList.toArray());
        }
        this.removeByIds(idList);
        String entrustCodes = String.join(",", entrustCodeList);
        autoLogUtils.deleteLog("环境试验-委托管理", String.format("删除了%d条委托单,委托单号:【%s】", idList.size(), entrustCodes));
    }

    @Override
    public HfEnvEntrustSaveVO queryVOById(String id) {
        HfEnvEntrustSaveVO hfEnvEntrustSaveVO = new HfEnvEntrustSaveVO();
        HfEnvEntrust hfEnvEntrust = this.getById(id);
        Assert.notNull(hfEnvEntrust, "委托数据不存在!");
        BeanUtils.copyProperties(hfEnvEntrust, hfEnvEntrustSaveVO);
        List<HfEnvPiece> pieceList = hfEnvPieceService.listByEntrustId(id);
        hfEnvEntrustSaveVO.setPieceInfo(pieceList);
        List<HfEnvProjectSaveVO> hfEnvProjectSaveVoList = hfEnvProjectService.listVOByEntrustId(id);
        hfEnvEntrustSaveVO.setProjectInfo(hfEnvProjectSaveVoList);
        List<BaseOssFiles> testOutlineList = MinioUtil.listByRefId(id, EntrustConsts.WTD_OUTLINE_REF_TYPE);
        hfEnvEntrustSaveVO.setTestOutlineFileList(testOutlineList);
        return hfEnvEntrustSaveVO;
    }

    @Override
    public HfEnvEntrust saveEntrust(HfEnvEntrustSaveVO hfEnvEntrustSaveVO) {
        HfEnvEntrust hfEnvEntrustNew = new HfEnvEntrust();
        BeanUtils.copyProperties(hfEnvEntrustSaveVO, hfEnvEntrustNew);

        // 保存主表
        Boolean isSubmit = hfEnvEntrustSaveVO.getIsSubmit();
        Boolean isAdd = hfEnvEntrustSaveVO.getId() != null;
        hfEnvEntrustNew.setStatus(EntrustConsts.WTD_STATUS_CG);
        String entrustCode = hfEnvEntrustSaveVO.getEntrustCode();

        List<HfEnvProjectSaveVO> hfEnvProjectList = Optional.ofNullable(hfEnvEntrustSaveVO.getProjectInfo()).orElse(new ArrayList<>());
        String unitTypeCode = hfEnvProjectList.isEmpty() ? null : hfEnvProjectList.get(0).getUnitType();
        hfEnvEntrustNew.setUnitTypeCode(unitTypeCode);
        String unitTypeName = "";
        if (StringUtils.isNotBlank(unitTypeCode)) {
            if (unitTypeCode.equals("1")) {
                unitTypeName = "气候";
            } else {
                unitTypeName = "力学";
            }
        }
        hfEnvEntrustNew.setUnitTypeName(unitTypeName);
        if (isSubmit) {
            // ✅ 校验当天排量
            validateDailyDisplacement(hfEnvEntrustSaveVO);

            if (Objects.isNull(entrustCode)) {
                entrustCode = baseSerialNoService.getMouthSerialNo("entrust", "yyMM", "", "", 3);
            }
            //  2411001  年份2位+月份2位+流水号3位
            hfEnvEntrustNew.setEntrustCode(entrustCode);
            hfEnvEntrustNew.setStatus(EntrustConsts.WTD_STATUS_TJ);
            this.saveOrUpdate(hfEnvEntrustNew);
            List<String> nextUserIdList = hfEnvEntrustSaveVO.getNextUserIdList();
            String flowId = submitEntrustFlow(hfEnvEntrustNew, nextUserIdList);
            hfEnvEntrustNew.setFlowId(flowId);
            this.updateById(hfEnvEntrustNew);
            autoLogUtils.modifyLog("试验管理-委托管理", String.format("提交委托单:【%s】", entrustCode));
            debugApiClient.syncEntrustStatus(hfEnvEntrustNew.getId());
        } else {
            this.saveOrUpdate(hfEnvEntrustNew);
        }
        //  获取主表id
        String mainId = hfEnvEntrustNew.getId();

        List<BaseOssFiles> testOutlineFileList = Optional.ofNullable(hfEnvEntrustSaveVO.getTestOutlineFileList())
                .orElse(new ArrayList<>(0));
        for (BaseOssFiles baseOssFiles : testOutlineFileList) {
            baseOssFiles.setRefId(mainId);
            baseOssFiles.setRefType(EntrustConsts.WTD_OUTLINE_REF_TYPE);
        }

        UpdateWrapper<BaseOssFiles> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda()
                .set(BaseOssFiles::getRefId, null)
                .eq(BaseOssFiles::getRefId, mainId)
                .eq(BaseOssFiles::getRefType, EntrustConsts.WTD_OUTLINE_REF_TYPE);
        baseOssFilesService.update(updateWrapper);
        baseOssFilesService.updateBatchById(testOutlineFileList);

        String productName = null;
        // 保存子表
        List<HfEnvPiece> hfEnvPieceList = hfEnvEntrustSaveVO.getPieceInfo();
        if (hfEnvPieceList != null && hfEnvPieceList.size() > 0) {
            for (int i = 0; i < hfEnvPieceList.size(); i++) {
                HfEnvPiece item = hfEnvPieceList.get(i);
                item.setId(null);
                item.setEntrustId(mainId);
                item.setSecretLevel(1);
                item.setStatus(PieceConsts.PIECE_STATUS_CG);
                item.setEntrustCode(entrustCode);
                item.setRowSort(i);
            }
            productName = hfEnvPieceList.get(0).getProductName();
        }
        hfEnvPieceService.removeByEntrustId(mainId);
        hfEnvPieceService.saveBatch(hfEnvPieceList);
        // 保存子表
        hfEnvProjectService.removeByEntrustId(mainId);

        if (hfEnvProjectList != null && hfEnvProjectList.size() > 0) {
            for (int i = 0; i < hfEnvProjectList.size(); i++) {
                HfEnvProjectSaveVO item = hfEnvProjectList.get(i);
                HfEnvProject hfEnvProject = new HfEnvProject();
                BeanUtils.copyProperties(item, hfEnvProject);
                List<BaseOssFiles> testPhotoList = Optional.ofNullable(item.getTestPhotoList()).orElse(new ArrayList<>());

                hfEnvProject.setId(null);
                hfEnvProject.setRowSort(i);
                hfEnvProject.setEntrustId(mainId);
                // ✅ 确保 unitType 字段正确保存
                hfEnvProject.setUnitType(item.getUnitType());

                System.out.println("保存项目: " + item.getUnitName() + ", unitType=" + item.getUnitType());
                hfEnvProjectService.save(hfEnvProject);
                String projectId = hfEnvProject.getId();

                for (BaseOssFiles testPhotoFile : testPhotoList) {
                    testPhotoFile.setRefId(projectId);
                    testPhotoFile.setRefType(EntrustConsts.WTD_TEST_PHONE);
                }


                UpdateWrapper<BaseOssFiles> testPhotoUpdateWrapper = new UpdateWrapper<>();
                testPhotoUpdateWrapper.lambda()
                        .set(BaseOssFiles::getRefType, null)
                        .eq(BaseOssFiles::getRefId, projectId)
                        .eq(BaseOssFiles::getRefType, EntrustConsts.WTD_TEST_PHONE);
                baseOssFilesService.update(testPhotoUpdateWrapper);

                baseOssFilesService.updateBatchById(testPhotoList);
            }
        }

        return hfEnvEntrustNew;
    }


    @Override
    public HfEnvEntrust saveDebugEntrust(HfEnvEntrustDebugSaveVO hfEnvEntrustDebugSaveVO) {
        HfEnvEntrust hfEnvEntrustNew = new HfEnvEntrust();
        BeanUtils.copyProperties(hfEnvEntrustDebugSaveVO, hfEnvEntrustNew);
        String mainId = hfEnvEntrustDebugSaveVO.getId();
        String entrustCode = null;
        String entrustUserCode = hfEnvEntrustDebugSaveVO.getEntrustUserCode();

        BaseOrgUserPlat entrustUser = baseOrgUserService.queryByUserCode(entrustUserCode);
        Assert.notNull(entrustUser, String.format("委托人:%s不存在!", entrustUserCode));
        hfEnvEntrustNew.setEntrustUserId(entrustUser.getId());
        hfEnvEntrustNew.setEntrustUserName(entrustUser.getIdName());

        String entrustCustId = hfEnvEntrustDebugSaveVO.getEntrustCustId();
        String entrustCust = hfEnvEntrustDebugSaveVO.getEntrustCust();


        // 保存主表
        if (StringUtils.isNotBlank(mainId)) {
            HfEnvEntrust hisEnvEntrust = getById(mainId);
            Assert.notNull(hisEnvEntrust, "委托单数据不存在!");
            entrustCode = hisEnvEntrust.getEntrustCode();
            hfEnvEntrustNew.setStatus(EntrustConsts.WTD_STATUS_CG);
            this.updateById(hfEnvEntrustNew);
        } else {
            hfEnvEntrustNew.setStatus(EntrustConsts.WTD_STATUS_CG);
            this.save(hfEnvEntrustNew);
            mainId = hfEnvEntrustNew.getId();
        }
        // 保存子表
        List<HfEnvPiece> hfEnvPieceList = hfEnvEntrustDebugSaveVO.getPieceInfo();
        if (hfEnvPieceList != null && hfEnvPieceList.size() > 0) {
            for (int i = 0; i < hfEnvPieceList.size(); i++) {
                HfEnvPiece item = hfEnvPieceList.get(i);
                item.setId(null);
                item.setEntrustId(mainId);
                item.setSecretLevel(1);
                item.setStatus(PieceConsts.PIECE_STATUS_CG);
                item.setEntrustCode(entrustCode);
                item.setRowSort(i);
            }
        }
        hfEnvPieceService.removeByEntrustId(mainId);
        hfEnvPieceService.saveBatch(hfEnvPieceList);
        // 保存子表
        hfEnvProjectService.removeByEntrustId(mainId);
        List<HfEnvProjectSaveVO> hfEnvProjectList = hfEnvEntrustDebugSaveVO.getProjectInfo();
        if (hfEnvProjectList != null && hfEnvProjectList.size() > 0) {
            for (int i = 0; i < hfEnvProjectList.size(); i++) {
                HfEnvProjectSaveVO item = hfEnvProjectList.get(i);
                HfEnvProject hfEnvProject = new HfEnvProject();
                BeanUtils.copyProperties(item, hfEnvProject);
                hfEnvProject.setId(null);
                hfEnvProject.setRowSort(i);
                hfEnvProject.setEntrustId(mainId);
                // ✅ 确保 unitType 字段正确保存
                hfEnvProject.setUnitType(item.getUnitType());
                System.out.println("保存项目: " + item.getUnitName() + ", unitType=" + item.getUnitType());
                hfEnvProjectService.save(hfEnvProject);
            }
        }
        return hfEnvEntrustNew;
    }

    /**
     * 校验当天排量
     * 规则：历史相同委托日期、同类型的委托单数量 + 1（当前） <= 当天排量数量
     *
     * @param hfEnvEntrustSaveVO 委托单保存VO
     */
    private void validateDailyDisplacement(HfEnvEntrustSaveVO hfEnvEntrustSaveVO) {
        // 1. 获取委托日期
        Date entrustTime = hfEnvEntrustSaveVO.getEntrustTime();
        System.out.println("======= 当天排量校验开始 =======");
        System.out.println("委托日期: " + entrustTime);

        if (entrustTime == null) {
            System.out.println("委托日期为空，跳过校验");
            return;
        }

        // 2. 获取项目类型（从第一个项目获取）
        List<HfEnvProjectSaveVO> projectInfo = hfEnvEntrustSaveVO.getProjectInfo();
        System.out.println("项目列表数量: " + (projectInfo != null ? projectInfo.size() : 0));

        if (projectInfo == null || projectInfo.isEmpty()) {
            System.out.println("项目列表为空，跳过校验");
            return;
        }

        String unitTypeCode = projectInfo.get(0).getUnitType();
        System.out.println("项目类型编码: " + unitTypeCode);

        if (com.hifar.fw.utils.lang.StringUtils.isEmpty(unitTypeCode)) {
            System.out.println("项目类型编码为空，跳过校验");
            return;
        }

        // 3. 查询当天排量记录
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = sdf.format(entrustTime);
        System.out.println("格式化日期: " + dateStr);

        QueryWrapper<HfDailyDisplacement> dailyWrapper = new QueryWrapper<>();
        dailyWrapper.apply("CAST(entrust_time AS DATE) = {0}", dateStr);
        dailyWrapper.eq("unit_type_code", unitTypeCode);
        dailyWrapper.ne("del_flag", 1);

        HfDailyDisplacement dailyDisplacement = dailyDisplacementService.getOne(dailyWrapper);
        System.out.println("查询当天排量结果: " + (dailyDisplacement != null ? dailyDisplacement.getId() : "未找到"));

        if (dailyDisplacement == null) {
            System.out.println("未配置当天排量，跳过校验（可选校验）");
            return;
        }

        Integer maxQuantity = dailyDisplacement.getQuantity();
        System.out.println("当天排量限制: " + maxQuantity);

        // 4. 统计历史相同日期、相同类型的委托单数量（不含当前编辑的委托单）
        QueryWrapper<HfEnvEntrust> entrustWrapper = new QueryWrapper<>();
        entrustWrapper.apply("CAST(entrust_time AS DATE) = {0}", dateStr);
        entrustWrapper.ne("del_flag", 1);

        // 编辑时排除自己
        String currentId = hfEnvEntrustSaveVO.getId();
        if (com.hifar.fw.utils.lang.StringUtils.isNotEmpty(currentId)) {
            entrustWrapper.ne("id", currentId);
            System.out.println("编辑模式，排除当前委托单ID: " + currentId);
        }

        List<HfEnvEntrust> historicalEntrustList = this.list(entrustWrapper);
        System.out.println("历史委托单总数: " + (historicalEntrustList != null ? historicalEntrustList.size() : 0));

        // 5. 统计历史委托单中相同类型的数量
        long historicalCount = 0;
        if (historicalEntrustList != null && !historicalEntrustList.isEmpty()) {
            for (HfEnvEntrust entrust : historicalEntrustList) {
                // 查询该委托单的项目列表，判断是否包含相同类型
                QueryWrapper<HfEnvProject> projectWrapper = new QueryWrapper<>();
                projectWrapper.eq("entrust_id", entrust.getId());
                projectWrapper.eq("unit_type", unitTypeCode);
                projectWrapper.ne("del_flag", 1);
                long count = hfEnvProjectService.count(projectWrapper);
                System.out.println("委托单[" + entrust.getEntrustCode() + "]包含" + unitTypeCode + "类型项目: " + count + "个");
                if (count > 0) {
                    historicalCount++;
                }
            }
        }

        System.out.println("历史相同类型委托单数量: " + historicalCount);

        // 6. 校验：历史数量 + 当前（1个） > 当天排量
        long totalCount = historicalCount + 1;
        System.out.println("总数量（历史 + 当前）: " + totalCount + " / 限制: " + maxQuantity);

        if (totalCount > maxQuantity) {
            String typeText = "1".equals(unitTypeCode) ? "气候" : "力学";
            String errorMsg = String.format("当天排量校验失败！%s的%s类型委托单已有%d个，当天排量限制为%d个，无法继续添加！",
                    dateStr, typeText, historicalCount, maxQuantity);
            System.out.println("❌ 校验失败: " + errorMsg);
            throw new RuntimeException(errorMsg);
        }

        System.out.println("✅ 当天排量校验通过");
        System.out.println("======= 当天排量校验结束 =======");
    }


    private String submitEntrustFlow(HfEnvEntrust hfEnvEntrust, List<String> nextUserIdList) {

        Assert.notNull(hfEnvEntrust, "委托数据不能为空!");
        String id = hfEnvEntrust.getId();
        String entrustCode = hfEnvEntrust.getEntrustCode();
        List<NodeUserBean> nextUserList = null;
        List<BaseOrgUserPlat> nextUserPlatList = new ArrayList<>();
        if (Objects.nonNull(nextUserIdList) && !nextUserIdList.isEmpty()) {
            nextUserList = new ArrayList(nextUserIdList.size());
            List<BaseOrgUserPlat> userPlatList = baseOrgUserService.listByIds(nextUserIdList);
            for (BaseOrgUserPlat userPlat : userPlatList) {
                NodeUserBean nodeUserBean = new NodeUserBean();
                nodeUserBean.setId(userPlat.getId());
                nodeUserBean.setName(userPlat.getIdName());
                nextUserList.add(nodeUserBean);
                nextUserPlatList.add(userPlat);
            }
        }


        String flowTitle = String.format("试验委托审批:[%s]", entrustCode);
        String flowId = hfEnvEntrust.getFlowId();
        String testPropertyCode = hfEnvEntrust.getTestPropertyCode();
        if (Objects.isNull(flowId)) {
            PriCreateBean createBean = new PriCreateBean();
            createBean.setBusiId(id);
            createBean.setProCode(FlowCodeConsts.ENTRUST_SUBMIT_FLOW);

            createBean.setProTitle(flowTitle);
            createBean.setPriAbstract(String.format("试验委托审批:[%s]", entrustCode));

            createBean.setNextUserList(nextUserList);
            Map<String, Object> valMap = new HashMap<>(1);
            valMap.put("testPropertyCode", testPropertyCode);
            createBean.getVarMap().putAll(valMap);
            BusiRequest requestParam = new BusiRequest();
            requestParam.getExt().put("userId", SystemLoginUser.userId);
            requestParam.getExt().put("idName", SystemLoginUser.idName);
            BusiResponseNetty proResponse = new BusiResponseNetty();
            BeanUtil.copyProperties(FlowApiUtils.createAndStartProcessInstance(requestParam, createBean), proResponse, true);
            Assert.isTrue(proResponse.getCode() == 200, proResponse.getMsg());
            Map<String, Object> resMap = (Map<String, Object>) proResponse.getData();
            Assert.notNull(resMap, "流程审批发起失败!");
            flowId = StringUtils.trimToNull((String) resMap.get("id"));

            for (BaseOrgUserPlat executeUserPlat : nextUserPlatList) {
                oaTaskClient.createTask(flowTitle, flowId, id, SystemLoginUser.userCode, executeUserPlat.getUserCode());
            }
            return StringUtils.trimToNull((String) resMap.get("id"));
        } else {
            BusiRequest requestParam = new BusiRequest();
            requestParam.getExt().put("userId", SystemLoginUser.userId);
            requestParam.getExt().put("idName", SystemLoginUser.idName);

            // 流程实例
            String queryPriSql = "select * from  flow_pri_base where id = {0} ";
            Map<String, Object> priMap = dataSourceService.selectOne(queryPriSql, flowId);

            // 任务列表
            String queryTaskSql = "select id from  flow_pri_task where pri_id ={0} and status={1} order by update_time desc,create_time desc";
            Map<String, Object> taskMap = dataSourceService.selectOne(queryTaskSql, flowId, FlowConst.TASK_STATUS_CREATE);

            String taskId = com.hifar.fw.utils.lang.StringUtils.trimNull(taskMap.get("id"));

            // 流程定义数据
            String prdId = com.hifar.fw.utils.lang.StringUtils.trimNull(priMap.get("prdId"));
            String queryProDataSql = "select to_char(pro_data) pro_data from  flow_prd_base where id = {0} ";
            Map<String, Object> prdMap = dataSourceService.selectOne(queryProDataSql, prdId);
            String proData = com.hifar.fw.utils.lang.StringUtils.trimNull(prdMap.get("proData"));
            List<Map<String, Object>> nodeList = (List<Map<String, Object>>) JsonUtils.toMap(proData).get("nodeList");

            // 下一个节点ID
            Map<String, Object> nextNode = nodeList.stream()
                    .filter(Objects::nonNull)
                    .filter(nodeMap -> "testAdminConfirm".equals(com.hifar.fw.utils.lang.StringUtils.trimNull(nodeMap.get("code"))))
                    .findFirst()
                    .get();
            String nextNodeId = com.hifar.fw.utils.lang.StringUtils.trimNull(nextNode.get("id"));
            TaskCommitBean bean = new TaskCommitBean();
            bean.setTaskId(taskId);
            bean.setRsStatus(1); // 审批状态 1 同意 2 不同意
            bean.setOpinion("发起人再次提交"); // 提交意见
            bean.setNextNodeId(nextNodeId); // 下一个节点ID
            bean.setNextUserList(nextUserList);
            bean.putVar("testPropertyCode", testPropertyCode);
            FlowApiUtils.commitTask(requestParam, bean);
            for (BaseOrgUserPlat executeUserPlat : nextUserPlatList) {
                oaTaskClient.createTask(flowTitle, flowId, id, SystemLoginUser.userCode, executeUserPlat.getUserCode());
            }
        }
        return flowId;
    }


    @Override
    public HfEnvEntrustSaveVO queryHfEnvEntrustVO(String mainId) {
        HfEnvEntrustSaveVO hfEnvEntrustSaveVO = new HfEnvEntrustSaveVO();
        HfEnvEntrust hfEnvEntrust = this.getById(mainId);
        Assert.notNull(hfEnvEntrust, "委托数据不存在!");
        BeanUtils.copyProperties(hfEnvEntrust, hfEnvEntrustSaveVO);
        List<HfEnvPiece> pieceList = hfEnvPieceService.listByEntrustId(mainId);
        hfEnvEntrustSaveVO.setPieceInfo(pieceList);
        List<HfEnvProjectSaveVO> hfEnvProjectSaveVOList = hfEnvProjectService.listVOByEntrustId(mainId);
        hfEnvEntrustSaveVO.setProjectInfo(hfEnvProjectSaveVOList);
        List<BaseOssFiles> testOutlineList = MinioUtil.listByRefId(mainId, EntrustConsts.WTD_OUTLINE_REF_TYPE);
        hfEnvEntrustSaveVO.setTestOutlineFileList(testOutlineList);
        return hfEnvEntrustSaveVO;
    }

    @Override
    public Page<HfEnvEntrustVO> pageVO(Page<HfEnvEntrustVO> page, QueryWrapper<HfEnvEntrustVO> queryWrapper) {
        Page<HfEnvEntrustVO> hfEnvEntrustVOPage = baseMapper.pageVO(page, queryWrapper);
        List<HfEnvEntrustVO> records = hfEnvEntrustVOPage.getRecords();

        // 获取所有委托单ID，用于批量查询附件数量
        List<String> entrustIdList = records.stream()
                .map(HfEnvEntrustVO::getId)
                .collect(Collectors.toList());

        // 批量查询附件数量
        Map<String, Integer> fileNumMap = baseOssFilesService.queryFileNum(entrustIdList, EntrustConsts.WTD_FILE_REF_TYPE);

        for (HfEnvEntrustVO entrustVO : records) {
            // 设置附件数量
            Integer fileNum = fileNumMap.getOrDefault(entrustVO.getId(), 0);
            entrustVO.setFileNum(fileNum);

            String qrPdfPath = entrustVO.getQrPdfPath();
            String dataPackagePath = entrustVO.getDataPackagePath();
            Integer secretLevel = entrustVO.getSecretLevel();
            if (StringUtils.isNotBlank(qrPdfPath)) {
                String qrPdfDownloadPath = MinioUtil.getFullFilePaths(MinioUtil.PRE_DEFAULT, qrPdfPath, secretLevel);
                entrustVO.setQrPdfPath(qrPdfDownloadPath);
            }
            if (StringUtils.isNotBlank(dataPackagePath)) {
                String dataPackageDownloadPath = MinioUtil.getFullFilePaths(MinioUtil.PRE_DEFAULT, dataPackagePath, secretLevel);
                entrustVO.setDataPackagePath(dataPackageDownloadPath);
            }
        }
        return hfEnvEntrustVOPage;
    }

    @Override
    public void supplementConditions(SupplementConditionsVO supplementConditionsVO) {
        String entrustId = supplementConditionsVO.getId();
        List<ProjectConditionsVO> projectConditionsVOList = supplementConditionsVO.getProjectList();
        List<HfEnvProject> projectList = new ArrayList<>(projectConditionsVOList.size());
        for (ProjectConditionsVO projectConditionsVO : projectConditionsVOList) {
            HfEnvProject hfEnvProject = new HfEnvProject();
            BeanUtils.copyProperties(projectConditionsVO, hfEnvProject);
            projectList.add(hfEnvProject);
        }
        hfEnvProjectService.updateBatchById(projectList);
    }

    @Override
    public void saveEntrustFile(HfEnvEntrustSaveFileVO hfEnvEntrustSaveFileVO) {
        String id = hfEnvEntrustSaveFileVO.getId();
        HfEnvEntrust hfEnvEntrust = getById(id);
        Assert.notNull(hfEnvEntrust, "数据不存在!");
        List<BaseOssFiles> filesList = hfEnvEntrustSaveFileVO.getFilesList();
        // WTD_FILE_REF_TYPE
        for (BaseOssFiles baseOssFiles : filesList) {
            baseOssFiles.setRefId(id);
            baseOssFiles.setRefType(EntrustConsts.WTD_FILE_REF_TYPE);
        }
        UpdateWrapper<BaseOssFiles> updateFileWrapper = new UpdateWrapper<>();
        updateFileWrapper.lambda()
                .set(BaseOssFiles::getRefId, null)
                .eq(BaseOssFiles::getRefId, id)
                .eq(BaseOssFiles::getRefType, EntrustConsts.WTD_FILE_REF_TYPE);
        baseOssFilesService.update(updateFileWrapper);
        baseOssFilesService.updateBatchById(filesList);
        autoLogUtils.addLog("试验管理-委托管理", String.format("上传委托单附件:【%s】", hfEnvEntrust.getEntrustCode()));
    }

    @Override
    public List<BaseOssFiles> queryEntrustFile(String id) {
        return MinioUtil.listByRefId(id, EntrustConsts.WTD_FILE_REF_TYPE, true);
    }


    @Override
    public void generateQrCodeFile(String id) {
        HfEnvEntrust envEntrust = this.getById(id);
        Assert.notNull(envEntrust, "数据不存在!");
        List<HfEnvPiece> entrustPieceList = hfEnvPieceService.listByEntrustId(id);
        List<HfEnvProject> entrustProjectList = hfEnvProjectService.listByEntrustId(id);
        String entrustCode = envEntrust.getEntrustCode();

        EntrustQRData entrustQRData = new EntrustQRData();
        BeanUtils.copyProperties(envEntrust, entrustQRData);
        List<EntrustPieceQrData> entrustPieceQrDataList = entrustPieceList.stream()
                .map(item -> {
                    EntrustPieceQrData entrustPieceQrData = new EntrustPieceQrData();
                    BeanUtils.copyProperties(item, entrustPieceQrData);
                    return entrustPieceQrData;
                }).collect(Collectors.toList());

        List<EntrustProjectQrData> entrustProjectQrDataList = entrustProjectList.stream()
                .map(item -> {
                    EntrustProjectQrData entrustProjectQrData = new EntrustProjectQrData();
                    BeanUtils.copyProperties(item, entrustProjectQrData);
                    return entrustProjectQrData;
                }).collect(Collectors.toList());
        entrustQRData.setPieceList(entrustPieceQrDataList);
        entrustQRData.setProjectList(entrustProjectQrDataList);
        String entrustQrData = JsonUtils.toJson(entrustQRData);
        List<String> qrDataList = ToolKit.splitStr(entrustQrData, QrDataConsts.QR_DATA_SIZE);
        int qrCount = qrDataList.size();
        Integer pageQRSize = QrDataConsts.PAGE_QR_SIZE;
        int pageSize = qrCount / pageQRSize;
        if (qrCount % pageQRSize > 0) {
            pageSize += 1;
        }
        Iterator<String> qrDataIterator = qrDataList.iterator();
        int qrSeq = 1;

//        List<Map<String, Object>> qrPageDataList = new ArrayList<>(pageSize);
        List<String> qrPdfPathList = new ArrayList<>(pageSize);
        File templateFile = null;
        try {
            templateFile = getResourceAsFile(QrDataConsts.TEMPLATE_PATH);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Assert.notNull(templateFile, "二维码模板文件不存在!");
        for (int i = 0; i < pageSize; i++) {
            Map<String, Object> qrPageDataMap = new HashMap<>();
            for (Integer integer = 0; integer < QrDataConsts.PAGE_QR_SIZE; integer++) {
                if (qrDataIterator.hasNext()) {
                    String dataText = qrDataIterator.next();
                    qrPageDataMap.put("entrustCode" + (integer + 1), String.format("单号:%s", entrustCode));
                    qrPageDataMap.put("seq" + (integer + 1), String.format("序号:%d", qrSeq));
                    qrPageDataMap.put("count" + (integer + 1), String.format("总数:%d", qrCount));
                    QrData qrData = new QrData();
                    qrData.setData(dataText);
                    qrData.setTotal(qrCount);
                    qrData.setCurrent(qrSeq);
                    qrData.setEntrustCode(entrustCode);
                    String qrDataText = JsonUtils.toJson(qrData);
                    byte[] imageBts = QRCodeUtil.generateQRCodeImageBts(qrDataText
                            , QrDataConsts.QR_CODE_WIDTH, QrDataConsts.QR_CODE_HEIGHT);
                    qrPageDataMap.put("QRCode" + (integer + 1), imageBts);
                    qrSeq++;
                } else {
                    break;
                }
            }
            String qrFilePath = FileUtil.getTempPath() + File.separator + IdUtils.uuid32() + ".pdf";
            ItextpdfUtil.insertFormFiledToPdf(templateFile, qrFilePath, qrPageDataMap);
            qrPdfPathList.add(qrFilePath);
        }
        String tempRootQrPdfPath = FileUtil.getTempPath() + File.separator + IdUtils.uuid32() + ".pdf";

        ItextpdfUtil.mergePdfFiles(qrPdfPathList, tempRootQrPdfPath);
        String qrPdfPath = "hifar/idm/" + entrustCode + "Qr.pdf";
        try {
            MinioUtil.uploadLocalFileToMinio(MinioUtil.PRE_DEFAULT, qrPdfPath, tempRootQrPdfPath, "application/pdf");
            UpdateWrapper<HfEnvEntrust> entrustUpdateWrapper = new UpdateWrapper<>();
            entrustUpdateWrapper.lambda()
                    .set(HfEnvEntrust::getQrPdfPath, qrPdfPath)
                    .eq(HfEnvEntrust::getId, id);
            this.update(entrustUpdateWrapper);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (new File(tempRootQrPdfPath).exists()) {
                new File(tempRootQrPdfPath).delete();
            }
            for (String tempPdfPath : qrPdfPathList) {
                new File(tempPdfPath).delete();
            }
        }
    }


    @Override
    public String generateQrCodeFile2(String id) {
        return envEntrustQrRender.renderReport(id);
    }

    public static File getResourceAsFile(String resourcePath) throws IOException {
        ClassPathResource resource = new ClassPathResource(resourcePath);

        try (InputStream inputStream = resource.getInputStream()) {
            // 创建临时文件
            Path tempFile = Files.createTempFile("temp-", resource.getFilename());
            Files.copy(inputStream, tempFile, StandardCopyOption.REPLACE_EXISTING);
            // 设置JVM退出时删除临时文件
            tempFile.toFile().deleteOnExit();
            return tempFile.toFile();
        }
    }

    @Override
    public HfEnvEntrustSaveVO querySubmitEntrustVO(String id) {
        HfEnvEntrustSaveVO hfEnvEntrustSaveVO = new HfEnvEntrustSaveVO();
        HfEnvEntrust hfEnvEntrust = this.getById(id);
        Assert.notNull(hfEnvEntrust, "委托数据不存在!");
        BeanUtils.copyProperties(hfEnvEntrust, hfEnvEntrustSaveVO);
        List<HfEnvPiece> pieceList = hfEnvPieceService.listByEntrustId(id);
        hfEnvEntrustSaveVO.setPieceInfo(pieceList);
        List<HfEnvProjectSaveVO> hfEnvProjectSaveVOList = hfEnvProjectService.listSubmitVOByEntrustId(id);
        hfEnvEntrustSaveVO.setProjectInfo(hfEnvProjectSaveVOList);
//        List<BaseOssFiles> testOutlineList = MinioUtil.listByRefId(mainId, EntrustConsts.WTD_OUTLINE_REF_TYPE,true);
        QueryWrapper<BaseOssFiles> fileQueryWrapper = new QueryWrapper<>();
        fileQueryWrapper.lambda()
                .eq(BaseOssFiles::getRefId, id)
                .eq(BaseOssFiles::getRefType, EntrustConsts.WTD_OUTLINE_REF_TYPE)
                .orderByAsc(BaseOssFiles::getRowSort);
        List<BaseOssFiles> testOutlineList = baseOssFilesService.list(fileQueryWrapper);

        hfEnvEntrustSaveVO.setTestOutlineFileList(testOutlineList);

        return hfEnvEntrustSaveVO;
    }


    @Override
    public void syncEntrustStatus() {
        List<HfEnvGkEntrust> gkEntrustList = gkEntrustService.lambdaQuery()
                .isNull(HfEnvGkEntrust::getEntrustId)
                .list();

        // 添加null检查
        if (gkEntrustList == null || gkEntrustList.isEmpty()) {
            log.info("没有需要同步的GK委托");
            return;
        }

        log.info("开始同步GK委托状态，共{}条", gkEntrustList.size());

        // 第一步：数据预处理和验证
        List<String> validEntrustCodes = new ArrayList<>();
        Map<String, HfEnvGkEntrust> gkEntrustMap = new HashMap<>();
        int skipCount = 0;

        for (HfEnvGkEntrust hfEnvGkEntrust : gkEntrustList) {
            String gkEntrustId = hfEnvGkEntrust.getId();
            String entrustCode = hfEnvGkEntrust.getEntrustCode();

            if (StringUtils.isBlank(gkEntrustId) || StringUtils.isBlank(entrustCode)) {
                skipCount++;
                log.debug("GK委托数据不完整，跳过，GK委托ID：{}，委托单号：{}", gkEntrustId, entrustCode);
                continue;
            }

            validEntrustCodes.add(entrustCode);
            gkEntrustMap.put(entrustCode, hfEnvGkEntrust);
        }

        if (skipCount > 0) {
            log.warn("跳过{}条数据不完整的GK委托", skipCount);
        }

        if (validEntrustCodes.isEmpty()) {
            log.warn("没有有效的委托单号可供同步");
            return;
        }

        // 第二步：批量查询SM委托（优化：一次查询替代N次查询）
        List<HfEnvEntrust> smEntrustList = this.lambdaQuery()
                .in(HfEnvEntrust::getEntrustCode, validEntrustCodes)
                .list();

        if (smEntrustList == null || smEntrustList.isEmpty()) {
            log.warn("根据{}个委托单号未查询到SM委托数据", validEntrustCodes.size());
            return;
        }

        // 构建SM委托映射：委托单号 -> SM委托
        Map<String, HfEnvEntrust> smEntrustMap = smEntrustList.stream()
                .filter(e -> StringUtils.isNotBlank(e.getEntrustCode()))
                .collect(Collectors.toMap(
                        HfEnvEntrust::getEntrustCode,
                        e -> e,
                        (v1, v2) -> v1
                ));

        log.info("批量查询到{}条SM委托数据", smEntrustMap.size());

        // 第三步：数据匹配和准备批量更新
        List<HfEnvEntrust> smEntrustUpdateList = new ArrayList<>();
        List<HfEnvGkEntrust> gkEntrustUpdateList = new ArrayList<>();
        List<String> syncEntrustIds = new ArrayList<>();
        Map<String, String> gkToSmIdMap = new HashMap<>();
        int successCount = 0;
        int notFoundCount = 0;

        for (Map.Entry<String, HfEnvGkEntrust> entry : gkEntrustMap.entrySet()) {
            String entrustCode = entry.getKey();
            HfEnvGkEntrust gkEntrust = entry.getValue();

            HfEnvEntrust smEntrust = smEntrustMap.get(entrustCode);
            if (smEntrust == null) {
                notFoundCount++;
                log.debug("SM委托不存在，跳过，委托单号：{}", entrustCode);
                continue;
            }

            String smEntrustId = smEntrust.getId();
            if (StringUtils.isBlank(smEntrustId)) {
                log.warn("SM委托ID为空，数据异常，委托单号：{}", entrustCode);
                continue;
            }

            // 更新SM委托
            smEntrust.setGkEntrustId(gkEntrust.getId());
            smEntrust.setStatus(gkEntrust.getStatus());
            smEntrustUpdateList.add(smEntrust);

            // 更新GK委托
            gkEntrust.setEntrustId(smEntrustId);
            gkEntrustUpdateList.add(gkEntrust);

            // 记录需要同步调试系统的ID
            syncEntrustIds.add(smEntrustId);

            // 记录映射关系用于子表更新
            gkToSmIdMap.put(gkEntrust.getId(), smEntrustId);

            successCount++;
        }

        if (notFoundCount > 0) {
            log.warn("有{}条GK委托在SM系统中找不到对应数据", notFoundCount);
        }

        if (successCount == 0) {
            log.warn("没有可同步的有效数据");
            return;
        }

        log.info("数据匹配完成，准备批量更新{}条记录", successCount);

        // 第四步：批量更新主表（优化：批量更新替代N次单条更新）
        if (!smEntrustUpdateList.isEmpty()) {
            this.updateBatchById(smEntrustUpdateList);
            log.info("批量更新SM委托完成，{}条", smEntrustUpdateList.size());
        }

        if (!gkEntrustUpdateList.isEmpty()) {
            gkEntrustService.updateBatchById(gkEntrustUpdateList);
            log.info("批量更新GK委托完成，{}条", gkEntrustUpdateList.size());
        }

        // 第五步：批量更新子表关联
        for (Map.Entry<String, String> entry : gkToSmIdMap.entrySet()) {
            String gkEntrustId = entry.getKey();
            String smEntrustId = entry.getValue();

            try {
                gkProjectService.updateEntrustId(gkEntrustId, smEntrustId);
                taskTestRelationService.updateEntrustId(gkEntrustId, smEntrustId);
                envTaskService.updateEntrustId(gkEntrustId, smEntrustId);
                gkPieceService.updateEntrustId(gkEntrustId, smEntrustId);
                reportService.updateEntrustId(gkEntrustId, smEntrustId);
            } catch (Exception e) {
                log.error("子表关联更新失败，GK委托ID：{}，SM委托ID：{}，错误：{}", gkEntrustId, smEntrustId, e.getMessage());
            }
        }

        log.info("子表关联更新完成，{}条", gkToSmIdMap.size());

        // 第六步：异步同步调试系统（不影响主流程）
        for (String entrustId : syncEntrustIds) {
            try {
                debugApiClient.syncEntrustStatus(entrustId);
            } catch (Exception e) {
                log.error("同步调试系统失败，委托ID：{}，错误：{}", entrustId, e.getMessage());
            }
        }

        log.info("委托主表同步完成，成功{}条，跳过{}条", successCount, skipCount + notFoundCount);

        // ======================================================================================
        // 阶段2：补充子表关联（处理孤立的子表数据）
        // ======================================================================================
        syncSubTableRelations();
    }

    /**
     * 同步子表关联关系
     * 处理那些主表已关联，但子表未关联的数据
     */
    private void syncSubTableRelations() {
        log.info("开始同步子表关联关系");

        // 收集所有子表中未关联的GK委托ID
        Set<String> gkEntrustIdSet = new HashSet<>();

        // 从5个子表收集未关联的GK委托ID
        gkEntrustIdSet.addAll(collectGkEntrustIds(
                gkProjectService.lambdaQuery().isNull(HfEnvGkProject::getEntrustId).list(),
                HfEnvGkProject::getGkEntrustId
        ));

        gkEntrustIdSet.addAll(collectGkEntrustIds(
                taskTestRelationService.lambdaQuery().isNull(HfEnvTaskTestRelation::getEntrustId).list(),
                HfEnvTaskTestRelation::getGkEntrustId
        ));

        gkEntrustIdSet.addAll(collectGkEntrustIds(
                envTaskService.lambdaQuery().isNull(HfEnvTask::getEntrustId).list(),
                HfEnvTask::getGkEntrustId
        ));

        gkEntrustIdSet.addAll(collectGkEntrustIds(
                gkPieceService.lambdaQuery().isNull(HfEnvGkPiece::getEntrustId).list(),
                HfEnvGkPiece::getGkEntrustId
        ));

        gkEntrustIdSet.addAll(collectGkEntrustIds(
                reportService.lambdaQuery().isNull(HfEnvReport::getEntrustId).list(),
                HfEnvReport::getGkEntrustId
        ));

        if (gkEntrustIdSet.isEmpty()) {
            log.info("没有需要补充关联的子表数据");
            return;
        }

        log.info("收集到{}个GK委托ID需要补充子表关联", gkEntrustIdSet.size());

        // 批量查询GK委托，获取关联的SM委托ID
        List<HfEnvGkEntrust> gkEntrustsList = Optional.ofNullable(
            gkEntrustService.listByIds(gkEntrustIdSet))
            .orElse(new ArrayList<>());

        if (gkEntrustsList.isEmpty()) {
            log.warn("根据GK委托ID集合查询不到GK委托数据");
            return;
        }

        // 构建映射：GK委托ID -> SM委托ID
        Map<String, String> gkEntrustIdMap = gkEntrustsList.stream()
                .filter(e -> StringUtils.isNotBlank(e.getId()) && StringUtils.isNotBlank(e.getEntrustId()))
            .collect(Collectors.toMap(
                HfEnvGkEntrust::getId,
                        HfEnvGkEntrust::getEntrustId,
                        (v1, v2) -> v1
                ));

        if (gkEntrustIdMap.isEmpty()) {
            log.warn("GK委托关联映射为空，跳过子表更新");
            return;
        }

        log.info("开始批量更新子表关联，共{}条映射关系", gkEntrustIdMap.size());

        // 批量更新子表关联
        int successCount = 0;
        int failCount = 0;

        for (Map.Entry<String, String> entry : gkEntrustIdMap.entrySet()) {
            String gkEntrustId = entry.getKey();
            String smEntrustId = entry.getValue();

            try {
                gkProjectService.updateEntrustId(gkEntrustId, smEntrustId);
                taskTestRelationService.updateEntrustId(gkEntrustId, smEntrustId);
                envTaskService.updateEntrustId(gkEntrustId, smEntrustId);
                gkPieceService.updateEntrustId(gkEntrustId, smEntrustId);
                reportService.updateEntrustId(gkEntrustId, smEntrustId);
                successCount++;
            } catch (Exception e) {
                failCount++;
                log.error("子表关联更新失败，GK委托ID：{}，SM委托ID：{}，错误：{}", gkEntrustId, smEntrustId, e.getMessage());
            }
        }

        log.info("子表关联更新完成，成功{}条，失败{}条", successCount, failCount);
    }

    /**
     * 从列表中收集非空的GK委托ID
     */
    private <T> Set<String> collectGkEntrustIds(List<T> list, java.util.function.Function<T, String> idExtractor) {
        if (list == null || list.isEmpty()) {
            return Collections.emptySet();
        }

        return list.stream()
                .map(idExtractor)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());
    }


    @Override
    public List<HfEnvReportTaskVO> queryEntrustTaskList(String entrustId) {
        List<HfEnvTask> taskList = envTaskService.reportListTaskByEntrustId(entrustId);
        List<HfEnvReportTaskVO> reportTaskVOList = new ArrayList<>(taskList.size());

        for (HfEnvTask hfEnvTask : taskList) {
            String taskId = hfEnvTask.getId();
            HfEnvReportTaskVO hfEnvReportTaskVO = new HfEnvReportTaskVO();
            BeanUtils.copyProperties(hfEnvTask, hfEnvReportTaskVO);
            List<HfEnvTaskTestVO> hfEnvTaskTestVOList = testService.reportListVoByTaskId(taskId);
            hfEnvReportTaskVO.setTestList(hfEnvTaskTestVOList);
            reportTaskVOList.add(hfEnvReportTaskVO);
        }
        return reportTaskVOList;
    }

    @Override
    public void generatePackageData(String id) {
        HfEnvEntrust hfEnvEntrust = this.getById(id);
        Assert.notNull(hfEnvEntrust, "数据不存在!");
        String entrustCode = hfEnvEntrust.getEntrustCode();

        List<HfEnvPiece> envPieceList = hfEnvPieceService.listByEntrustId(id);
        List<HfEnvProject> projectList = hfEnvProjectService.listByEntrustId(id);

        String tempPath = FileUtil.getTempPath();
        String baseTempPath = tempPath + File.separator + IdUtils.uuid32();
        File baseTempFile = new File(baseTempPath);
        if (!baseTempFile.exists()) {
            baseTempFile.mkdirs();
        }
        File entrustDataFile = new File(baseTempPath + File.separator + DataPackageConsts.ENTRUST_FILE_NAME);
        File pieceDataFile = new File(baseTempPath + File.separator + DataPackageConsts.PIECE_FILE_NAME);
        File projectDataFile = new File(baseTempPath + File.separator + DataPackageConsts.PROJECT_FILE_NAME);
        File fileDataFile = new File(baseTempPath + File.separator + DataPackageConsts.FILE_FILE_NAME);

        List<BaseOssFiles> filesList = baseOssFilesService.lambdaQuery()
            .eq(BaseOssFiles::getRefId, id)
            .list();

        HfEnvEntrustDataPackageVO hfEnvEntrustDataPackageVO = new HfEnvEntrustDataPackageVO();
        BeanUtils.copyProperties(hfEnvEntrust, hfEnvEntrustDataPackageVO);

        String entrustUserId = hfEnvEntrustDataPackageVO.getEntrustUserId();
        String entrustUserCode = Optional.ofNullable(baseOrgUserService.getById(entrustUserId))
            .map(BaseOrgUserPlat::getUserCode).orElse(null);
        hfEnvEntrustDataPackageVO.setEntrustUserCode(entrustUserCode);

        String entrustCustId = hfEnvEntrustDataPackageVO.getEntrustCustId();

        String entrustCustCode = Optional.ofNullable(baseOrgDeptPlatService.getById(entrustCustId))
            .map(BaseOrgDeptPlat::getDeptCode).orElse(null);
        hfEnvEntrustDataPackageVO.setEntrustCustCode(entrustCustCode);

        String entrustFileDataJson = JsonUtils.toJson(filesList);
        String entrustDataJson = JsonUtils.toJson(hfEnvEntrustDataPackageVO);
        String pieceDataJson = JsonUtils.toJson(envPieceList);
        String projectDataJson = JsonUtils.toJson(projectList);
        ToolKit.writeFile(entrustDataFile, entrustDataJson, "UTF-8");
        ToolKit.writeFile(pieceDataFile, pieceDataJson, "UTF-8");
        ToolKit.writeFile(projectDataFile, projectDataJson, "UTF-8");
        ToolKit.writeFile(fileDataFile, entrustFileDataJson, "UTF-8");

        for (BaseOssFiles baseOssFile : filesList) {
            String fileName = baseOssFile.getFileName();
            String bucketPre = baseOssFile.getBucketPre();
            String filePath = baseOssFile.getFilePath();
            try {
                String fileBasePath = filePath.substring(0, filePath.lastIndexOf("/"));
                String downloadTempBasePath = baseTempPath + File.separator + bucketPre + File.separator + fileBasePath;
                File downloadTempBaseDirFile = new File(downloadTempBasePath);
                if (!downloadTempBaseDirFile.exists()) {
                    downloadTempBaseDirFile.mkdirs();
                }
                String downloadTempFilePath = baseTempPath + File.separator + bucketPre + File.separator + filePath;
                MinioUtil.downloadFileToLocal(bucketPre, filePath, downloadTempFilePath);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        String encryptZipPath = FileUtil.getTempPath() + File.separator + IdUtils.uuid32() + ".zip";
        File zip = null;
        try {
            zip = ZipUtil.zip(baseTempPath);
            String fileName = String.format("数据包_%s", entrustCode);
            String dataPackagePath = "hifar/entrustData/" + fileName + ".zip";
            MinioUtil.uploadLocalFileToMinio(MinioUtil.PRE_DEFAULT, dataPackagePath, zip.getAbsolutePath());
            this.lambdaUpdate()
                    .set(HfEnvEntrust::getDataPackagePath, dataPackagePath)
                    .eq(HfEnvEntrust::getId, id)
                    .update();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (Objects.nonNull(zip)) {
                zip.delete();
            }
            File encryptZip = new File(encryptZipPath);
            if (encryptZip.exists()) {
                encryptZip.delete();
            }
            try {
                FileUtils.deleteDirectory(new File(baseTempPath));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void cancel(String id) {
        HfEnvEntrust envEntrust = getById(id);
        Assert.notNull(envEntrust, "委托数据不存在!");
        envEntrust.setStatus(EntrustConsts.WTD_STATUS_CANCEL);
        this.updateById(envEntrust);

        String flowId = envEntrust.getFlowId();
        if (StringUtils.isNotBlank(flowId)) {
            BusiRequest request = new BusiRequest();
            request.putData("taskId", flowId);
            request.putData("priId", flowId);
            Map<String, Object> extMap = new HashMap<>();
            extMap.put("userId", SystemLoginUser.userId);
            extMap.put("idName", SystemLoginUser.idName);
            request.setExt(extMap);
            FlowApiUtils.killPriOfTask(request);
        }
        debugApiClient.syncEntrustStatus(id);
        autoLogUtils.deleteLog("试验管理-委托管理", String.format("作废委托单:【%s】", StringUtils.trimToNull(envEntrust.getEntrustCode())));
    }

    @Override
    public BusiResponse validateDailyDisplacement(Date entrustTime, String unitTypeCode, String id) {
        log.info("======= 当日排量校验开始 =======");
        log.info("委托日期: {}, 类型编码: {}, 委托单ID: {}", entrustTime, unitTypeCode, id);

        // 1. 参数校验
        if (entrustTime == null) {
            log.error("委托日期为空");
            return BusiResponse.error(400, "委托日期不能为空!");
        }
        if (StringUtils.isBlank(unitTypeCode)) {
            log.error("类型编码为空");
            return BusiResponse.error(400, "类型编码不能为空!");
        }

        // 2. 格式化委托日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = sdf.format(entrustTime);
        log.info("格式化日期: {}", dateStr);

        // 3. 查询当日排量配置
        QueryWrapper<HfDailyDisplacement> dailyWrapper = new QueryWrapper<>();
        dailyWrapper.apply("CAST(entrust_time AS DATE) = {0}", dateStr);
        dailyWrapper.eq("unit_type_code", unitTypeCode);
        dailyWrapper.eq("del_flag", 0);

        HfDailyDisplacement dailyDisplacement = dailyDisplacementService.getOne(dailyWrapper);
        log.info("查询当日排量结果: {}", dailyDisplacement != null ? dailyDisplacement.getId() : "未配置");

        if (dailyDisplacement == null) {
            log.info("未配置当日排量，校验通过（不限制）");
            Map<String, Object> resultData = new HashMap<>();
            resultData.put("historicalCount", 0);
            resultData.put("maxQuantity", null);
            resultData.put("available", true);
            log.info("======= 当日排量校验结束 =======");
            return BusiResponse.OK(resultData);
        }

        Integer maxQuantity = dailyDisplacement.getQuantity();
        log.info("当日排量限制: {}", maxQuantity);

        // 4. 统计历史委托单数量（非草稿状态、同日期、同类型）
        QueryWrapper<HfEnvEntrust> entrustWrapper = new QueryWrapper<>();
        entrustWrapper.apply("CAST(entrust_time AS DATE) = {0}", dateStr);
        entrustWrapper.ne("status", EntrustConsts.WTD_STATUS_CG); // 排除草稿状态
        entrustWrapper.eq("del_flag", 0);

        // 编辑时排除自己
        if (StringUtils.isNotBlank(id)) {
            entrustWrapper.ne("id", id);
            log.info("编辑模式，排除当前委托单ID: {}", id);
        }

        List<HfEnvEntrust> historicalEntrustList = this.list(entrustWrapper);
        log.info("历史委托单总数: {}", historicalEntrustList != null ? historicalEntrustList.size() : 0);

        // 5. 统计历史委托单中包含相同类型项目的数量
        long historicalCount = 0;
        if (historicalEntrustList != null && !historicalEntrustList.isEmpty()) {
            for (HfEnvEntrust entrust : historicalEntrustList) {
                // 查询该委托单是否包含相同类型的项目
                QueryWrapper<HfEnvProject> projectWrapper = new QueryWrapper<>();
                projectWrapper.eq("entrust_id", entrust.getId());
                projectWrapper.eq("unit_type", unitTypeCode);
                projectWrapper.eq("del_flag", 0);
                long count = hfEnvProjectService.count(projectWrapper);
                if (count > 0) {
                    historicalCount++;
                    log.info("委托单[{}]包含{}类型项目", entrust.getEntrustCode(), unitTypeCode);
                }
            }
        }

        log.info("历史相同类型委托单数量: {}", historicalCount);

        // 6. 校验：历史数量 < 当日排量数量
        Map<String, Object> resultData = new HashMap<>();
        resultData.put("historicalCount", historicalCount);
        resultData.put("maxQuantity", maxQuantity);

        if (historicalCount < maxQuantity) {
            resultData.put("available", true);
            log.info("✅ 当日排量校验通过: 历史数量({}) < 限制({})", historicalCount, maxQuantity);
            log.info("======= 当日排量校验结束 =======");
            return BusiResponse.OK(resultData);
        } else {
            resultData.put("available", false);
            String typeText = "1".equals(unitTypeCode) ? "气候" : "力学";
            String errorMsg = String.format("当天排量校验失败！%s的%s类型委托单已有%d个，当天排量限制为%d个，无法继续添加！",
                    dateStr, typeText, historicalCount, maxQuantity);
            log.error("❌ 校验失败: {}", errorMsg);
            log.info("======= 当日排量校验结束 =======");
            return BusiResponse.error(400, errorMsg);
        }
    }

}
